/*============================================================================

The Medical Imaging Interaction Toolkit (MITK)

Copyright (c) German Cancer Research Center (DKFZ)
All rights reserved.

Use of this source code is governed by a 3-clause BSD license that can be
found in the LICENSE file.

============================================================================*/

#ifndef MODEL_FIT_FUNCTOR_BASE_H
#define MODEL_FIT_FUNCTOR_BASE_H

#include <itkObject.h>

#include <mitkVector.h>

#include "mitkModelBase.h"
#include "mitkSVModelFitCostFunction.h"

#include "MitkModelFitExports.h"

namespace mitk
{

  class MITKMODELFIT_EXPORT ModelFitFunctorBase: public ::itk::Object
  {
  public:
    typedef ModelFitFunctorBase Self;
    typedef itk::Object Superclass;
    typedef itk::SmartPointer< Self >                            Pointer;
    typedef itk::SmartPointer< const Self >                      ConstPointer;

    itkTypeMacro(ModelFitFunctorBase, itk::Object);

    typedef ScalarType ParameterImagePixelType;
    typedef std::vector<ParameterImagePixelType> InputPixelArrayType;
    typedef std::vector<ParameterImagePixelType> OutputPixelArrayType;

    /** Returns the values determined by fitting the passed model. The values in the returned vector are ordered in the
     * following sequence:
       * - model parameters (see also GetParameterNames())
       * - derived model parameters (see also GetDerivedParameterNames())
       * - criterion(s) (see also GetCriterionNames())
       * - evaluation parameters (see also GetEvaluationParameterNames())
       * @param value Signal the model should be fitted onto
       * @param model Pointer to the preconfigured/ready to use model instance for the fitting against the signal curve
       * @param initialParameters parameters of the model that should be used as starting point of the fitting process.
       * @pre model must point to a valid instance.
       * @pre Size of initialParameters must be equal to model->GetNumberOfParameters().
       */
    OutputPixelArrayType Compute(const InputPixelArrayType& value, const ModelBase* model,
                                 const ModelBase::ParametersType& initialParameters) const;

    /** Returns the number of outputs the fit functor will return if compute is called.
     * The number depends in parts on the passed model.
     * @exception Exception will be thrown if no valid model is passed.*/
    unsigned int GetNumberOfOutputs(const ModelBase* model) const;

    typedef ModelBase::ParameterNamesType ParameterNamesType;

    /** Returns names of all evaluation parameters defined by the user*/
    ParameterNamesType GetEvaluationParameterNames() const;
    void ResetEvaluationParameters();
    void RegisterEvaluationParameter(const std::string& parameterName,
                                     SVModelFitCostFunction* evaluationCostFunction);
    const SVModelFitCostFunction* GetEvaluationParameterCostFunction(const std::string& parameterName)
    const;

    /** Returns names of the criterion used to fit the model. */
    virtual ParameterNamesType GetCriterionNames() const = 0 ;

    /** Returns names of the depug parameters generated by the functor.
     Is empty, if debug is deactivated. */
    ParameterNamesType GetDebugParameterNames() const;

    itkBooleanMacro(DebugParameterMaps);
    itkSetMacro(DebugParameterMaps, bool);
    itkGetConstMacro(DebugParameterMaps, bool);

  protected:

    typedef ModelBase::ParametersType ParametersType;
    typedef ModelFitCostFunctionInterface::SignalType SignalType;

    ModelFitFunctorBase();

    ~ModelFitFunctorBase() override;

    /**Internal Method called by Compute to get the final criterion values thar dove the fit.
     must be implemented be concrete functor classes.*/
    virtual OutputPixelArrayType GetCriteria(const ModelBase* model, const ParametersType& parameters,
        const SignalType& sample) const = 0;

    /** Internal Method called by Compute().
      Gets all derived parameters of the models with the final found parameters of the fit.*/
    OutputPixelArrayType GetDerivedParameters(const ModelBase* model,
        const ParametersType& parameters) const;

    /** Internal Method called by Compute().
      Gets the evaluation parameters for all cost functions enlisted by the user, based on
      the model with the final found parameters of the fit and the input signal.*/
    OutputPixelArrayType GetEvaluationParameters(const ModelBase* model,
        const ParametersType& parameters, const SignalType& sample) const;

    typedef std::map<std::string, ParameterImagePixelType> DebugParameterMapType;

    /** Internal Method called by Compute(). It does the real fit and returns the found parameters.
    Additionally it must return its debug parameter via debugParameters.
    @post If m_DebugParameterMaps is true, it must return all debug parameters defined by
    GetDebugParameterNames() via debugParameters.
    @param value Signal the Model should be fitted against
    @param model Pointer to the model that should be fitted
    @param initialParameters Initial modal parameters for the fit
    @param [out] debugParameters Map containing all debug parameters for the done fit (must only valid if m_DebugParameterMap is true)*/
    virtual ParametersType DoModelFit(const SignalType& value, const ModelBase* model,
                                      const ModelBase::ParametersType& initialParameters,
                                      DebugParameterMapType& debugParameters) const = 0;

    /** Returns names of the depug parameters generated by the functor. Will be called by GetDebugParameterNames,
    if debug is activated. */
    virtual ParameterNamesType DefineDebugParameterNames()const = 0;

  private:

    typedef std::map<std::string, SVModelFitCostFunction::Pointer> CostFunctionMapType;
    CostFunctionMapType m_CostFunctionMap;
    bool m_DebugParameterMaps;
    ::itk::SimpleFastMutexLock m_Mutex;
  };

}


#endif // MODEL_FIT_FUNCTOR_BASE_H
